<script setup lang="ts">
import { ref, onMounted, PropType, watch } from 'vue'
import * as THREE from 'three'
import { useTexture } from '@tresjs/core'
import { materialList, textureKeys, materialTextureTypes } from '@/packages/public/chart'
import { deepClone, getDownUrl } from '@/utils'
// 类型定义
interface MaterialConfig {
  [key: string]: any
}
interface MaterialItem {
  type: string
  config: MaterialConfig
  key?: string | number
  textureType?: string
}

const props = defineProps({
  item: { type: Object as PropType<MaterialItem>, required: true }
})

const materialData = ref({})
const componentKey = ref(0)

// 1. 添加贴图缓存
const textureCache = {}

const loadTextureWithCache = async url => {
  // 移除时间戳参数以便缓存
  const baseUrl = url.split('?')[0]

  if (!textureCache[baseUrl]) {
    console.log('加载新贴图:', baseUrl)
    const texture = await useTexture(url)

    // 优化贴图设置
    texture.generateMipmaps = false // 禁用mipmap生成
    texture.minFilter = THREE.LinearFilter // 使用简单过滤
    texture.anisotropy = 1 // 降低各向异性过滤

    textureCache[baseUrl] = texture
  }

  return textureCache[baseUrl]
}
const ossUrl = import.meta.env.VITE_GLOB_OSS_URL
// 加载和准备材质数据
const prepareMaterial = async () => {
  try {
    // 基本检查
    if (!props.item || !props.item.config) {
      console.warn('缺少材质配置')
      return
    }

    const config = { ...props.item.config }

    // 根据材质类型限制可用贴图键，避免无效 define 触发编译错误
    const allowedKeys = (materialTextureTypes as any)[props.item.type]
      ? (materialTextureTypes as any)[props.item.type].map((t: any) => t.value)
      : []

    // 收集贴图配置（仅限当前材质支持的贴图键）
    const textureConfig: Record<string, string> = {}

    // 预清理：把当前材质不支持的贴图键从配置中移除，并强制设为 null，避免 three 开启无效的 USE_* 宏
    const sanitizedConfig: Record<string, any> = { ...config }
    textureKeys.forEach(k => {
      if (allowedKeys.length && !allowedKeys.includes(k)) {
        delete sanitizedConfig[k]
        sanitizedConfig[k] = null
      }
    })

    for (const key in config) {
      if (textureKeys.includes(key) && config[key]) {
        // 过滤掉当前材质不支持的贴图键（比如 MeshToon 不支持 roughnessMap/metalnessMap/displacementMap 等）
        if (allowedKeys.length && !allowedKeys.includes(key)) continue
        // 添加时间戳避免缓存
        const u = config[key]
        if (typeof config[key] === 'string' && u.includes('http')) {
          textureConfig[key] = ossUrl + getDownUrl(u) + (u.includes('?') ? '&' : '?') + 'v=' + Date.now()
        } else {
          textureConfig[key] = ossUrl + u
        }
      }
    }

    // 加载贴图
    if (Object.keys(textureConfig).length > 0) {
      try {
        const textures = await useTexture(textureConfig)

        // 处理贴图
        for (const key in textures) {
          if (textures[key] && textures[key].isTexture) {
            // 设置贴图需要更新
            textures[key].needsUpdate = true

            // 特别处理自发光贴图
            if (key === 'emissiveMap') {
              // 确保自发光贴图有正确的UV设置
              textures[key].wrapS = THREE.RepeatWrapping
              textures[key].wrapT = THREE.RepeatWrapping
            }

            // Toon 渐变贴图推荐的采样方式
            if (key === 'gradientMap') {
              textures[key].generateMipmaps = false
              textures[key].minFilter = THREE.NearestFilter
              textures[key].magFilter = THREE.NearestFilter
            }
          }
        }

        // 如果有自发光贴图，确保设置发光颜色
        if ((textures as any).emissiveMap) {
          ;(materialData.value as any).emissive = new THREE.Color(0xffffff)
          ;(materialData.value as any).emissiveIntensity = (materialData.value as any).emissiveIntensity ?? 1.0
        }

        // 若存在 roughnessMap/metalnessMap，确保基础标量存在（仅 Standard/Physical 有意义）
        if ((textures as any).roughnessMap) {
          ;(materialData.value as any).roughness = (materialData.value as any).roughness ?? 1.0
        }
        if ((textures as any).metalnessMap) {
          ;(materialData.value as any).metalness = (materialData.value as any).metalness ?? 0.0
        }
        // 对于允许的贴图键，如果未成功加载贴图（例如本地字符串），强制置为 null，避免被当作 truthy 值
        allowedKeys.forEach((k: string) => {
          if (k in sanitizedConfig && !(k in textures)) {
            sanitizedConfig[k] = null
          }
        })

        // 合并配置（仅使用已净化的配置）
        materialData.value = {
          ...sanitizedConfig,
          ...textures
        }
      } catch (error) {
        console.error('贴图加载错误:', error)
        materialData.value = config
      }
    } else {
      // 无贴图时也要使用净化后的配置，避免字符串落到 *Map 字段
      const sanitizedNoTex: Record<string, any> = { ...sanitizedConfig }
      allowedKeys.forEach((k: string) => {
        if (k in sanitizedNoTex && typeof sanitizedNoTex[k] !== 'object') sanitizedNoTex[k] = null
      })
      materialData.value = sanitizedNoTex
    }

    // 强制重新渲染
    componentKey.value++
  } catch (error) {
    console.error('材质准备错误:', error)
  }
}

// 监听配置变化
watch(() => props.item, prepareMaterial, { deep: true, immediate: true })

// 初始化
onMounted(prepareMaterial)
</script>

<template>
  <component
    v-if="props.item && props.item.type"
    :is="'Tres' + props.item.type"
    :key="componentKey"
    v-bind="materialData"
  />
</template>
